package cn.net.mugui.net.pc.task;

import java.util.Enumeration;
import java.util.concurrent.ConcurrentHashMap;

import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameRecorder;
import org.bytedeco.javacv.VideoInputFrameGrabber;

import com.mugui.base.base.Autowired;
import com.mugui.base.base.Component;
import com.mugui.base.client.net.auto.AutoTask;
import com.mugui.base.client.net.base.Task;
import com.mugui.base.client.net.task.TaskImpl;
import com.mugui.base.util.Other;

import cn.net.mugui.net.pc.panel.WebCamUI;

/**
 * 推流任务
 * 
 * @author mugui
 *
 */
@AutoTask
@Component
@Task
public class PushTask extends TaskImpl {

	@Override
	public void run() {
		while (true) {
			if (map.isEmpty()) {
				synchronized (map) {
					if (map.isEmpty()) {
						try {
							map.wait();
							continue;
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			}
			Enumeration<String> keys = map.keys();
			if (keys.hasMoreElements()) {
				String nextElement = keys.nextElement();
				try {
					recordCamera(nextElement, 30);
				} catch (Exception e) {
					e.printStackTrace();
					return;
				}
			}
			Other.sleep(25);
		}
	}

	@Autowired
	public WebCamUI webCamUI;
	FFmpegFrameRecorder recorder = null;

	public void recordCamera(String outputFile, double frameRate)
			throws Exception, InterruptedException, FrameRecorder.Exception {
		// 0代表的是第一个摄像头，如果是笔记本外接的usb摄像头时应该改为1，以此类推
		// 这里使用javacv的抓取器，至于使用的是ffmpeg还是opencv，请自行查看源码
		VideoInputFrameGrabber grabber = VideoInputFrameGrabber.createDefault(0);
//		// 开启抓取器
		grabber.start();
//		// 抓取一帧视频并将其转换为图像，至于用这个图像用来做什么？加水印，人脸识别等等自行添加
		Frame image = grabber.grab();
		if (is_zhibo) {
			recorder = initRecorder(stmp, image.imageWidth, image.imageHeight, frameRate);
		}
		long time = 0;
		while (map.get(outputFile) != null) {
			try {
				Frame grabPacket = grabber.grabFrame();
				if (grabPacket == null) {
					grabber.close();
					grabber = VideoInputFrameGrabber.createDefault(0);
					grabber.start();
					break;
				}
				
				if (!is_zhibo && recorder != null) {
					break;
				} else if (is_zhibo && recorder == null) {
					break;
				}
				if (recorder != null) {
					if (time == 0) {
						time = System.currentTimeMillis();
					}
					recorder.setTimestamp((System.currentTimeMillis() - time) * 1000);
					recorder.record(grabPacket);
					
				}
				webCamTask.add(grabPacket);

			} catch (Exception e) {
				e.printStackTrace();
			}

		}
		if (recorder != null) {
			recorder.stop();
			recorder = null;
		}
		grabber.close();
	}

	private FFmpegFrameRecorder initRecorder(String outputFile, int imageWidth, int imageh, double frameRate)
			throws org.bytedeco.javacv.FFmpegFrameRecorder.Exception {
		FFmpegFrameRecorder recorder = FFmpegFrameRecorder.createDefault(outputFile, imageWidth, imageh);
		// avcodec.AV_CODEC_ID_H264，编码
		recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
		recorder.setVideoBitrate((int) (imageWidth * imageh * frameRate));
		// 封装格式，如果是推送到rtmp就必须是flv封装格式
		recorder.setFormat("flv");
		recorder.setGopSize(50);

		recorder.setOption("rtsp_transport", "tcp");
		recorder.setOption("stimeout", "10000000");
		// 提升编码速度
		recorder.setOption("preset", "ultrafast");// 降低编码延时
		recorder.setOption("tune", "zerolatency");
		recorder.setFrameRate(frameRate);

		recorder.setVideoOption("rtsp_transport", "tcp");
		recorder.setVideoOption("stimeout", "10000000");
		// 提升编码速度
		recorder.setVideoOption("preset", "ultrafast");// 降低编码延时
		recorder.setVideoOption("tune", "zerolatency");
		recorder.start();// 开启录制器
		return recorder;
	}

	@Autowired
	WebCamTask webCamTask;

	ConcurrentHashMap<String, byte[]> map = new ConcurrentHashMap<>();
	boolean is_zhibo = false;
	String stmp = null;

	public void startZhibo(String stmp) {
		is_zhibo = true;
		this.stmp = stmp;
	}

	public void stopZhibo() {
		is_zhibo = false;
	}

	public void start(String url) {
		synchronized (map) {

			map.put(url, new byte[0]);
			map.notifyAll();
		}
	}

	public void stop(String url) {
		synchronized (map) {
			map.remove(url);
			map.notifyAll();
		}
	}
}
